package be.ipl.diapero.uccImpl;

import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.ejb.EJB;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Stateless;

import be.ipl.diapero.dao.JoueurDao;
import be.ipl.diapero.dao.PartieDao;
import be.ipl.diapero.dao.TourDao;
import be.ipl.diapero.domaine.Joueur;
import be.ipl.diapero.domaine.Partie;
import be.ipl.diapero.domaine.Tour;
import be.ipl.diapero.domaine.Partie.Etat;
import be.ipl.diapero.exceptions.ArgumentInvalideException;
import be.ipl.diapero.exceptions.PartieExistanteException;
import be.ipl.diapero.exceptions.PartieInaccessibleException;
import be.ipl.diapero.ucc.GestionPartie;
import be.ipl.diapero.util.Util;

@Stateless
public class GestionPartieImpl implements GestionPartie {
	@EJB
	JoueurDao joueurDao;

	@EJB
	PartieDao partieDao;

	@EJB
	TourDao tourDao;
	
	@Override
	public Partie creerPartie(String nom) throws ArgumentInvalideException, PartieExistanteException {
		if (Util.checkNullEmpty(nom))
            throw new ArgumentInvalideException();

		if (partieDao.rechercher(nom) != null) throw new PartieExistanteException();

		Partie partie = new Partie(nom, new GregorianCalendar());
		partie = this.partieDao.enregistrer(partie);
		return partie;
	}
	
	@Override
	public boolean commencerPartie(Partie partie) {
		partie = partieDao.rechercher(partie.getId());
		partie = this.partieDao.chargerJoueurs(partie);
		partie = this.partieDao.chargerTours(partie);
		if (partie.getJoueurs().size() < 2)
			return false;
		return partie.commencerPartie();
	}


	@Override
	public boolean annulerPartie(Partie partie) {
		partie = partieDao.rechercher(partie.getId());
		if (partie.annulerPartie()) {
			partieDao.supprimer(partie.getId());
			partie = null;
			return true;
		}
		return false;
	}
	
	@Override
	public boolean rejoindrePartie(Partie partie, Joueur joueur) throws PartieInaccessibleException {
		if (partie == null) return false;
		if(partie.getEtat() != Etat.EN_ATTENTE) throw new PartieInaccessibleException();
		partie = partieDao.rechercher(partie.getId());
		partie = this.partieDao.chargerJoueurs(partie);
		partie = this.partieDao.chargerTours(partie);
		if (partie.ajouterJoueur(joueur)) {
			if (partie.getJoueurs().size() >= Partie.MAX_JOUEURS) {
				partie.commencerPartie();
			}
			return true;
		}
		return false;
	}

	@Override
	public Partie chargerPartie(Partie partie) {
		partie = this.partieDao.chargerJoueurs(partie);
		return this.partieDao.chargerTours(partie);
	}
	
	@Override
	public boolean estEnCours(Partie partie) {
		partie = partieDao.rechercher(partie.getId());
		return partie.getEtat() == Etat.EN_COURS;
	}

	@Override
	@Lock(LockType.READ)
	public Map<String, Integer> getJoueursGemmes(Partie partie) {
		partie = partieDao.rechercher(partie.getId());
		partie = this.partieDao.chargerJoueurs(partie);
		partie = this.partieDao.chargerTours(partie);
		Map<String, Integer> joueursGemmesMap = new HashMap<String, Integer>();
		for (Joueur joueur : partie.getJoueurs()) {
			joueursGemmesMap.put(joueur.getPseudo(), partie.getGemmes(joueur));
		}
		return joueursGemmesMap;
	}

	@Override
	public Joueur getVainqueur(Partie partie) {
		partie = this.partieDao.chargerJoueurs(partie);
		partie = this.partieDao.chargerTours(partie);
		return partie.getVainqueur();
	}

	@Override
	@Lock(LockType.READ)
	public List<Joueur> listerJoueurs(Partie partie) {
		partie = partieDao.rechercher(partie.getId());
		partie = this.partieDao.chargerJoueurs(partie);
		partie = this.partieDao.chargerTours(partie);
		return partie.getJoueurs();
	}

	@Override
	@Lock(LockType.READ)
	public List<Partie> listerParties() {
		return this.partieDao.lister();
	}

	@Override
	@Lock(LockType.READ)
	public List<Partie> listerPartiesEnAttente() {
		return this.partieDao.listerPartiesEtat(Etat.EN_ATTENTE);
	}

	@Override
	@Lock(LockType.READ)
	public List<Partie> listerPartiesTerminees() {
		return this.partieDao.listerPartiesEtat(Etat.TERMINE);
	}
	
	@Override
	@Lock(LockType.READ)
	public List<Partie> listerPartiesEnCours() {
		return this.partieDao.listerPartiesEtat(Etat.EN_COURS);
	}

	@Override
	@Lock(LockType.READ)
	public Partie rechercherPartie(int id) {
		return this.partieDao.rechercher(id);
	}

	@Override
	public boolean terminerPartie(Partie partie) {
		partie = partieDao.rechercher(partie.getId());
		if (partie.terminerPartie()) {
			partie = null;
			return true;
		}
		return false;
	}

	@Override
	@Lock(LockType.READ)
	public Tour tourSuivant(Partie partie) {
		partie = partieDao.rechercher(partie.getId());
		partie = this.partieDao.chargerJoueurs(partie);
		partie = this.partieDao.chargerTours(partie);
		Tour tour = partie.commencerTourSuivant();
		if (tour == null)
			return null;
		return tourDao.enregistrer(tour);
	}

}
